﻿//using Nemerle.Collections;
using Nemerle.Text;
using Nemerle.Utility;

using System;
using System.Collections.Generic;
using System.Linq;

namespace Nemerle.Data.Function
{
  public module Functions
  {
    /// <summary>
    /// Identity function. 
    /// </summary>
    public Id[T](x : T) : T { x }
    
    /// <summary>
    /// Constant function.
    /// </summary>
    public Const[T, R](x : R) : T -> R { (_ => x) }
    
    /// <summary>
    /// Flips the order of arguments of a function.
    /// </summary>
    /// <param name="f">The function.</param>
    /// <returns>The function with flipped arguments.</returns>
    public Flip[T, U, R](f : T * U -> R) : U * T -> R
    {
      (a, b) => f(b, a)   
    }
    
    /// <summary>
    /// Flips the order of arguments of a curried function.
    /// </summary>
    /// <param name="f">The function.</param>
    /// <returns>The function with flipped arguments.</returns>
    public Flip[T, U, R](f : T -> U -> R) : U -> T -> R
    {
      a => b => f(b)(a)   
    }
    
    /// <summary>
    /// Converts an uncurried function to a curried function. 
    /// </summary>
    public Curry[T, U, R](f : T * U -> R) : T -> U -> R
    {
      a => b => f(a, b)   
    }
    
    /// <summary>
    /// Converts a curried function to a function on pairs.
    /// </summary>
    public UnCurry[T, U, R](f : T -> U -> R) : T * U -> R
    {
      (a, b) => f(a)(b)
    }
    
    /// <summary>
    /// Application.
    /// </summary>
    public Apply[T, R](f : T -> R, x : T) : R { f(x) }
    
    
    public On[T, U, R](this bf : T * T -> R, f : U -> T) : U * U -> R
    {
      (a, b) => bf(f(a), f(b))   
    }
    
    /// <summary>
    /// Fixed-point (Y) combinator.
    /// </summary>
    public Fix[T, R](f : (T -> R) -> (T -> R)) : T -> R
    {
      f(x => Fix(f)(x))
    }
  }
}
